package com.insmess.speech.common.util;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import com.insmess.speech.common.constant.PathConstant;
import com.insmess.speech.dto.HotWordDto;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.ListUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 热词替换实体
 */
@Slf4j
public class HotWordUtils {
    /**
     * 拼音集合
     */
    private static final Map<String, List<String>> PIN_YIN_MAP = new HashMap<>();

    /**
     * 多音集合
     */
    private static final Map<String, String> POLYPHONES_MAP = new HashMap<>();

    /**
     * 存储热词的集合
     */
    private static final List<String> HOT_WORD_LIST = new ArrayList<>();

    /**
     * 存储热词的文件
     */
    private static final String HOT_WORD_LIST_FILE;

    static {
        readPinYin();
        readPolyphones();
        //初始化热词存储集合
        HOT_WORD_LIST_FILE = PathConstant.INSMESS_SPEECH_PATH + File.separator + "storage" + File.separator + "hot_word_list";
        File sensitiveWordFile = new File(HOT_WORD_LIST_FILE);
        if (!sensitiveWordFile.getParentFile().exists()) {
            sensitiveWordFile.getParentFile().mkdirs();
        }
        if (sensitiveWordFile.exists()) {
            log.info("热词文件已存在，读取热词文件：{}", HOT_WORD_LIST_FILE);
            readHotWord();
        } else {
            //创建该文件
            try {
                sensitiveWordFile.createNewFile();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }

    /**
     * 获取热词列表
     * @return
     */
    public static List<HotWordDto> getSensitiveWordList() {
        return HOT_WORD_LIST.stream().map(str -> new HotWordDto(str.split("-")[0], str.split("-")[1])).collect(Collectors.toList());
    }

    /**
     * 添加热词
     * @return
     */
    public static void addSensitiveWord(HotWordDto hotWordDto) {
        String item = hotWordDto.getPinYin() + "-" + hotWordDto.getHanZi();
        HOT_WORD_LIST.add(item);
        writeSensitiveWord();
    }

    /**
     * 删除热词
     * @return
     */
    public static void removeSensitiveWord(String pinYin) {
        for (int i = 0; i < HOT_WORD_LIST.size(); i++) {
            String item = HOT_WORD_LIST.get(i);
            if (item.split("-")[0].equals(pinYin)) {
                HOT_WORD_LIST.remove(i);
                break;
            }
        }
    }

    @SneakyThrows
    private static void readHotWord() {
        List<String> list = FileUtils.readLines(new File(HOT_WORD_LIST_FILE), "utf-8");
        HOT_WORD_LIST.clear();
        HOT_WORD_LIST.addAll(list);
    }

    @SneakyThrows
    private static void writeSensitiveWord() {
        FileUtils.writeLines(new File(HOT_WORD_LIST_FILE), HOT_WORD_LIST);
    }

    public static String hotWord(String content) {
        List<HotWordDto> sensitiveWordList = getSensitiveWordList();
        Map<String, String> map = new HashMap<>();
        for (HotWordDto hotWordDto : sensitiveWordList) {
            map.put(hotWordDto.getPinYin(), hotWordDto.getHanZi());
        }
        return hotWord(content, map);
    }

    /**
     * 热词替换
     * @param content
     * @param hotMap
     * @return
     */
    public static String hotWord(String content, Map<String, String> hotMap) {
        List<String> originList = replaceWordToList(content);
        List<String> destList = new ArrayList<>(originList);
        //替换目标集合成英文
        replacePinYin(destList);
        //替换热词
        Set<String> keys = hotMap.keySet();
        //定义集合，保存被替换的索引。
        List<Integer> indexList = new ArrayList<>();
        for (String key : keys) {
            //转成字节数组
            String[] hotWords = splitPinYin(key);
            String[] valueArr = splitHanZi(hotMap.get(key));
            ArrayList<String> hotWordList = ListUtil.toList(hotWords);

            //获取小集合在大集合中的索引
            int index;
            while ((index = Collections.indexOfSubList(destList, hotWordList)) != -1) {
                //替换
                for (int i = index; i < index + hotWordList.size(); i++) {
                    destList.set(i, valueArr[i - index]);
                    indexList.add(i);
                }
            }
        }
        //其他内容还原
        for (int i = 0; i < destList.size(); i++) {
            String value = destList.get(i);
            if (!value.equals(originList.get(i)) && !indexList.contains(i)) {
                destList.set(i, originList.get(i));
            }
        }
        StringBuilder sb = new StringBuilder();
        for (String s : destList) {
            sb.append(s);
        }
        return sb.toString();
    }

    /**
     * 替换拼音
     * @param contentList
     * @return
     */
    private static void replacePinYin(List<String> contentList) {
        //替换多音词
        while (true) {
            if (!replaceDuoYin(contentList)) {
                break;
            }
        }
        //替换拼音
        for (int i = 0; i < contentList.size(); i++) {
            String word = contentList.get(i);
            //判断拼音字典中是否包含
            if (PIN_YIN_MAP.containsKey(word)) {
                contentList.set(i, PIN_YIN_MAP.get(word).get(0));
            }
        }
    }
    public static boolean replaceDuoYin(List<String> contentList) {
        //先替换多音列表
        Set<String> duoYinKeys = POLYPHONES_MAP.keySet();
        for (String key : duoYinKeys) {
            //转成字节数组
            List<String> duoYinList = new ArrayList<>();
            char[] charArray = key.toCharArray();
            String values = POLYPHONES_MAP.get(key);
            String[] valueArr = values.split(",");
            for (char c : charArray) {
                duoYinList.add("" + c);
            }
            //获取小集合在大集合中的索引
            int index = Collections.indexOfSubList(contentList, duoYinList);
            if (index != -1) {
                //替换
                for (int i = index; i < index + duoYinList.size(); i++) {
                    contentList.set(i, valueArr[i - index]);
                }
                return true;
            }
        }
        return false;
    }




    private static List<String> replaceWordToList(String content) {
        List<String> list = new ArrayList<>();
        String str = "";
        char[] cArr = content.toCharArray();
        for (int i = 0; i < cArr.length; i++) {
            char c = cArr[i];
            if ((c + "").matches("[\\w]")) {
                str += c;
                if (i == cArr.length - 1) {
                    list.add(str);
                    str = "";
                } else if ((cArr[i + 1] + "").matches("[\\W]")){
                    list.add(str);
                    str = "";
                }
            } else {
                list.add(c + "");
            }
        }
        return list;
    }

    private static void readPinYin() {
        try (InputStream in = HotWordUtils.class.getClassLoader().getResourceAsStream("word/pinyins.txt")) {
            List<String> list = IOUtils.readLines(in, "utf-8");
            for (String line : list) {
                String[] split = line.split("-");
                String word = split[0];
                String pinYin = split[1];
                String[] splitPinYin = pinYin.split(",");
                PIN_YIN_MAP.put(word, CollUtil.toList(splitPinYin));
            }
            log.info("初始化拼音配置成功");
        } catch (Exception e) {
            throw new RuntimeException("初始化配置失败");
        }
    }

    private static void readPolyphones() {
        try (InputStream in = HotWordUtils.class.getClassLoader().getResourceAsStream("word/polyphones.txt")) {
            List<String> list = IOUtils.readLines(in, "utf-8");
            for (String line : list) {
                String[] split = line.split("-");
                String word = split[0];
                String pinYin = split[1];
//                pinYin = pinYin.replace(",", "");
                POLYPHONES_MAP.put(word, pinYin);
            }
            log.info("初始化多音配置成功");
        } catch (Exception e) {
            throw new RuntimeException("初始化配置失败");
        }
    }

    private static String[] splitPinYin(String pinYin) {
        List<String> list = new ArrayList<>();
        String str = "";
        char[] cArr = pinYin.toCharArray();
        for (char c : cArr) {
            str += c;
            if ((c + "").matches("[012345]")) {
                list.add(str);
                str = "";
            }
        }
        return list.toArray(new String[]{});
    }

    private static String[] splitHanZi(String HanZi) {
        List<String> list = new ArrayList<>();
        char[] cArr = HanZi.toCharArray();
        for (char c : cArr) {
            list.add(c + "");
        }
        return list.toArray(new String[]{});
    }

    public static void main(String[] args) {
        Map<String, String> map = new HashMap<>();
        map.put("bei3jing1", "北经");
        String word = hotWord("我今天去word3了趟北京吃了阿胶，北京天安门很好word", map);
        System.out.println(word);

    }


}
